#include <string.h>
#include <stdio.h>
#include <stdbool.h>

#include "main.h"
#include "fatfs.h"

#include "wav.h"

#include "menu.h"
#include "audio.h"
// #include "st7789.h"

#define  PRN  printf

// __attribute__((at(0x24000000))) uint8_t Buffer_Block_Tx[4];
// __attribute__((at(0x24040000))) uint8_t Buffer_Block_Rx[4];

// __attribute__((section (".RAM_D1"))) uint16_t 	buff_A[WAV_BUF_SIZE];
// __attribute__((section (".RAM_D1"))) uint16_t	buff_B[WAV_BUF_SIZE];

// __attribute__((at(0x24070000))) uint16_t 	buff_A[WAV_BUF_SIZE];
// __attribute__((at(0x24060000))) uint16_t	buff_B[WAV_BUF_SIZE];

char	header[512];
int		headSize;

uint16_t	buffer_size;

static uint32_t getChunkSize(char *head);

static char *getChunkId(char *head, char *buf);

static int getHeadSize(char *head);

static int ShowFileInfo(char *head);

static void frame_24_32(uint8_t *data);

static void set_volume(int bps, int size, int16_t *data);

/***

***/
void process_wav_buffer(void)
{
	Is_Process_buffer = false;
	
	if(Is_finished) {

		audio_Stop();

		printf("\r\nplay finished  %02d:%02d\r\n", min, sec);
		
		f_close(&SDFile);

		Play_Next();
		return ;

	} else {
		// a<->b
		pAudio->exchange  = pAudio->play_buff;
		pAudio->play_buff = pAudio->read_buff;
		pAudio->read_buff = pAudio->exchange;

		printf("remain : %d ---\r", pAudio->dataSize);

		if(Is_End_chunk) {
			Is_finished = true;
			return;
		}

		Is_Busy = 1;
		if(pAudio->dataSize < buffer_size) {

			retSD = f_read(&SDFile, (char *)pAudio->read_buff, pAudio->dataSize, &pAudio->bytesRead);
			Is_End_chunk = true;

		} else {
			retSD = f_read(&SDFile, (char *)pAudio->read_buff, buffer_size, &pAudio->bytesRead);
		}
		Is_Busy = 0;

		if(retSD != FR_OK) {
			printf("f_read() failed, res = %d\r\n", retSD);
			f_close(&SDFile);
			Is_finished = true;
		} else {
			// printf("read read_buff %d bytes OK  remain : %d\r\n", bytesRead, dataSize);
			pAudio->dataSize -= pAudio->bytesRead;

			if(pAudio->bitsPerSamplePerChannel == 16) {

				if(volume)	set_volume(16, pAudio->bytesRead / 2, (int16_t *)pAudio->read_buff);

			} else if(pAudio->bitsPerSamplePerChannel == 24) {

				frame_24_32((uint8_t *)pAudio->read_buff);
				if(volume)	set_volume(24, pAudio->bytesRead / 3, (int16_t *)pAudio->read_buff);
			}

		}
	}
}

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
int Wav_Play(char *fname)
{
	Is_Process_buffer = false;
	Is_finished = false;
	Is_End_chunk = false;

	memset(pAudio, 0x00, sizeof(AUDIO_DEV));

	retSD = f_open(&SDFile, fname, FA_READ);
	if(retSD != FR_OK) {
		printf("f_open()  %s failed, res = %d\r\n", fname, retSD);
		return -1;
	}

	printf("\r\n>>>Open: %s OK\r\n", fname);

	memset(header, 0x00, 512);

	retSD = f_read(&SDFile, header, 512, &pAudio->bytesRead);
	if((retSD != FR_OK) || (pAudio->bytesRead != 512)) {
		printf("f_read() failed, res = %d  bytesRead = %u\r\n", retSD, pAudio->bytesRead);
		f_close(&SDFile);
		return -10;
	} else {
		printf("read header %u bytes OK\r\n", pAudio->bytesRead);
	}

	headSize = ShowFileInfo(header);
	if((headSize < 0) || (headSize != 44)) {
		printf("------ headSize : %d ------\r\n", headSize);
		f_close(&SDFile);

		Play_Next();
		return -1;
	}

	pAudio->dataSize -= headSize;

	f_lseek(&SDFile, headSize);

	if(pAudio->bitsPerSamplePerChannel == 16) {
		buffer_size = 32768;  //  32 * 1024

		pAudio->buff_A = (uint16_t *)buffPointer;
		pAudio->buff_B = (uint16_t *)&buffPointer[buffer_size];
		memset(buffPointer, 0x00, buffer_size * 2);

		retSD = f_read(&SDFile, (char *)(pAudio->buff_A + headSize), buffer_size - headSize, &pAudio->bytesRead); // 保持对齐，减去 44字节
		if(retSD != FR_OK) {
			printf("f_read() buff_A failed, res = %d\r\n", retSD);
			f_close(&SDFile);
			return -10;
		} else {
			printf("read buffer A OK %d\r\n", pAudio->bytesRead);
			pAudio->dataSize -= pAudio->bytesRead;
			// 计算播放字节数，16bit
			pAudio->play_size = (uint16_t)(buffer_size);
			if(volume)	set_volume(16, pAudio->bytesRead / 2, (int16_t *)pAudio->buff_A);
		}

		retSD = f_read(&SDFile, (uint8_t *)pAudio->buff_B, buffer_size, &pAudio->bytesRead);
		if(retSD != FR_OK) {
			printf("f_read() buff_B failed, res = %d\r\n", retSD);
			f_close(&SDFile);
			return -11;
		} else {
			printf("read buffer B OK %d\r\n", pAudio->bytesRead);
			pAudio->dataSize -= pAudio->bytesRead;
			if(volume)	set_volume(16, pAudio->bytesRead / 2, (int16_t *)pAudio->buff_B);
		}
		// 24 bits
	} else if(pAudio->bitsPerSamplePerChannel == 24) {

		buffer_size = 36864;  //  36 * 1024

		pAudio->buff_A = (uint16_t *)buffPointer;
		pAudio->buff_B = (uint16_t *)&buffPointer[buffer_size + buffer_size / 3];
		memset(buffPointer, 0x00, buffer_size * 8 / 3 );

		for(int x = 72; x > 16; x--) {
			if(((x * 512 - headSize) % 3) == 0) {
				headSize = buffer_size - x * 512 + headSize;
				break;
			}
		}
		// headSize = 36864 - buffer_size;

		retSD = f_read(&SDFile, (char *)(pAudio->buff_A + headSize), buffer_size - headSize, &pAudio->bytesRead);	// 保持对齐，减去 44字节
		if(retSD != FR_OK) {
			printf("f_read() buff_A failed, res = %d\r\n", retSD);
			f_close(&SDFile);
			return -10;
		} else {
			printf("read buffer A OK %d\r\n", pAudio->bytesRead);
			pAudio->dataSize -= pAudio->bytesRead;

			frame_24_32((uint8_t *)pAudio->buff_A);
			// 计算播放字节数，24bit
			pAudio->play_size = (uint16_t)((buffer_size) * 4 / 3);
			if(volume)	set_volume(24, pAudio->bytesRead / 3, (int16_t *)pAudio->buff_A);

		}

		retSD = f_read(&SDFile, (uint8_t *)pAudio->buff_B, buffer_size, &pAudio->bytesRead);
		if(retSD != FR_OK) {
			printf("f_read() buff_B failed, res = %d\r\n", retSD);
			f_close(&SDFile);
			return -11;
		} else {
			pAudio->dataSize -= pAudio->bytesRead;
			printf("read buffer B OK %d\r\n", pAudio->bytesRead);
			frame_24_32((uint8_t *)pAudio->buff_B);
			if(volume)	set_volume(24, pAudio->bytesRead / 3, (int16_t *)pAudio->buff_B);
		}

	} else {
		// f_close(&SDFile);
		Play_Next();
		return 0;
	}

	pAudio->play_buff = pAudio->buff_A;
	pAudio->read_buff = pAudio->buff_B;

	printf("Play_Size = %d\r\n", pAudio->play_size);
	
	audio_Start();

	return 0;
}


static int ShowFileInfo(char *head)
{
	int offset;
	uint32_t skip;
	uint32_t ChunkSize;

	char chunkId[8];

	offset = 0;

	getChunkId(head + offset, chunkId);		// [RIFF]
	if(memcmp(chunkId, "RIFF", 4) != 0) {
		printf("Wrong WAV signature at offset 0: 0x%02X 0x%02X 0x%02X 0x%02X\r\n", head[0], head[1], head[2], head[3]);
		return -3;
	}
	offset += 4;
	ChunkSize = getChunkSize(head + offset);
	offset += 4;

	pAudio->fileSize = 8 + ChunkSize;

	getChunkId(head + offset, chunkId);		// [WAVE]
	if(memcmp(chunkId, "WAVE", 4) != 0) {
		printf("Wrong WAV signature at offset 8: 0x%02X 0x%02X 0x%02X 0x%02X\r\n", head[8], head[9], head[10], head[11]);
		return -4;
	}
	offset += 4;

	getChunkId(head + offset, chunkId);		// [fmt ]
	if(memcmp(chunkId, "fmt ", 4) != 0) {
		printf("Wrong WAV signature at offset 12: 0x%02X 0x%02X 0x%02X 0x%02X\r\n", head[12], head[13], head[14], head[15]);
		return -4;
	}
	offset += 4;

	skip = getChunkSize(head + offset);
	pAudio->headerSizeLeft = skip;
	offset += 4;

	pAudio->compression = head[offset] | (head[offset + 1] << 8);
	pAudio->channelsNum = head[offset + 2] | (head[offset + 3] << 8);
	pAudio->sampleRate = head[offset + 4] | (head[offset + 5] << 8) | (head[offset + 6] << 16) | (head[offset + 7] << 24);
	pAudio->bytesPerSecond = head[offset + 8] | (head[offset + 9] << 8) | (head[offset + 10] << 16) | (head[offset + 11] << 24);
	pAudio->bytesPerSample = head[offset + 12] | (head[offset + 13] << 8);
	pAudio->bitsPerSamplePerChannel = head[offset + 14] | (head[offset + 15] << 8);

	offset += skip;

	getChunkId(head + offset, chunkId);		// [data]
	offset += 4;

	while(memcmp(chunkId, "data", 4) != 0) {
		skip = getChunkSize(head + offset);
		offset += 4;

		offset += skip;

		getChunkId(head + offset, chunkId);
		offset += 4;

		if(offset > 500) break;
	}

	pAudio->dataSize = getChunkSize(head + offset);
	offset += 4;

	PRN(
	    "\r\n--- WAV header ---\r\n"
	    "File size: %u\r\n"
	    "Header size left: %u\r\n"
	    "Compression (1 = no compression): %u\r\n"
	    "Channels num: %d\r\n"
	    "Sample rate: %u\r\n"
	    "Bytes per second: %u\r\n"
	    "Bytes per sample: %d\r\n"
	    "Bits per sample per channel: %u\r\n"
	    "Data size: %u\r\n"
	    "Total time: %02d:%02d\r\n"
	    "------------------\r\n",
	    pAudio->fileSize, pAudio->headerSizeLeft, pAudio->compression, pAudio->channelsNum, pAudio->sampleRate,
	    pAudio->bytesPerSecond, pAudio->bytesPerSample, pAudio->bitsPerSamplePerChannel, pAudio->dataSize,
	    pAudio->dataSize / pAudio->bytesPerSecond / 60, pAudio->dataSize / pAudio->bytesPerSecond % 60);

	printf("\r\n");

	/***
	if(headerSizeLeft != 16) {
		printf("Wrong `headerSizeLeft` value, 16 expected\r\n");
		f_close(&SDFile);
		return -6;
	}
	***/

	if(pAudio->compression != 1) {
		printf("Wrong `compression` value, 1 expected\r\n");
		return -7;
	}

	if(pAudio->channelsNum != 2) {
		printf("Wrong `channelsNum` value, 2 expected\r\n");
		return -8;
	}

	/***
	if((sampleRate != 44100) || (bytesPerSample != 4) || (bitsPerSamplePerChannel != 16) || (bytesPerSecond != 44100 * 2 * 2)) {
		printf("Wrong file format, 16 bit file with sample rate 44100 expected\r\n");
		f_close(&SDFile);
		return -9;
	}
	***/

	printf("offset = %d\r\n", offset);
	return offset;

}

// 封装24bit 为 32bit
static void frame_24_32(uint8_t *data)
{
	int8_t x, y, z;
	int k, pos_3, pos_4;

	k = pAudio->bytesRead / 3;
	pos_3 = k * 3;
	pos_4 = k * 4;

	while((--k) > 0) {

		pos_3 -= 3;
		pos_4 -= 4;

		//  32bit     0    1    2    3
		//             \   \         /
		//  24bit       1   2       0
		data[pos_4 + 3] = data[pos_3 + 0];
		data[pos_4 + 2] = 0;
		data[pos_4 + 1] = data[pos_3 + 2];
		data[pos_4 + 0] = data[pos_3 + 1];

	}

	x = data[0];
	y = data[1];
	z = data[2];

	data[3] = x;
	data[2] = 0;
	data[1] = z;
	data[0] = y;

}

static void set_volume(int bps, int size, int16_t *data)
{
	// 调整音量临时指针
	uint16_t  num_vol;
	int16_t   *temp_vol;
	// int32_t   *temp_vol_24;
	int32_t   vol;

	temp_vol = data;

	if(bps == 16) {

		for(num_vol = 0; num_vol < size; num_vol++)
			*temp_vol++ >>= volume;

	} else if(bps == 24) {
		
		for(num_vol = 0; num_vol < size; num_vol++) {
			vol = temp_vol[num_vol * 2 + 1] | ((temp_vol[num_vol * 2]) << 16);
			
			vol >>= volume;
			
			temp_vol[num_vol * 2 + 1] = (int16_t)(vol & 0xffff);
			temp_vol[num_vol * 2] = (int16_t)((vol >> 16) & 0xffff);
			// *temp_vol_24++ >>= (volume-1);
		}
	}
}


static uint32_t getChunkSize(char *head)
{
	uint32_t size;
	size = head[0] | (head[1] << 8) | (head[2] << 16) | (head[3] << 24);
	printf("ChunkSize = %u\r\n", size);
	return size;

}

static char *getChunkId(char *head, char *buf)
{
	memcpy(buf, head, 4);
	printf("Chunk ID : [%c%c%c%c]\r\n", buf[0], buf[1], buf[2], buf[3]);
	return buf;
}

static int getHeadSize(char *head)
{
	int offset;
	int skip;

	char chunkId[8];

	offset = 0;
	getChunkId(head + offset, chunkId);		// [RIFF]
	offset += 4;
	getChunkSize(head + offset);
	offset += 4;

	getChunkId(head + offset, chunkId);		// [WAVE]
	offset += 4;

	getChunkId(head + offset, chunkId);		// [fmt ]
	offset += 4;

	skip = getChunkSize(head + offset);
	offset += 4;

	offset += skip;

	getChunkId(head + offset, chunkId);		// [data]
	offset += 4;

	while(memcmp(chunkId, "data", 4) != 0) {
		skip = getChunkSize(head + offset);
		offset += 4;

		offset += skip;

		getChunkId(head + offset, chunkId);
		offset += 4;

		if(offset > 500) break;
	}

	offset += 4;

	printf("offset = %d\r\n", offset);
	return offset;

}

static int ShowFileInfo00(void)
{
	// memcpy(header, buff_A, 44);

	/***
	if(memcmp((const char *)header, "RIFF", 4) != 0) {
		printf("Wrong WAV signature at offset 0: 0x%02X 0x%02X 0x%02X 0x%02X\r\n", header[0], header[1], header[2], header[3]);
		f_close(&SDFile);
		return -3;
	}

	if(memcmp((const char *)header + 8, "WAVEfmt ", 8) != 0) {
		printf("Wrong WAV signature at offset 8!\r\n");
		f_close(&SDFile);
		return -4;
	}

	if(memcmp((const char *)header + 36, "data", 4) != 0) {
		printf("Wrong WAV signature at offset 36!\r\n");
		f_close(&SDFile);
		return -5;
	}
	***/

	pAudio->fileSize = 8 + (header[4] | (header[5] << 8) | (header[6] << 16) | (header[7] << 24));
	pAudio->headerSizeLeft = header[16] | (header[17] << 8) | (header[18] << 16) | (header[19] << 24);
	pAudio->compression = header[20] | (header[21] << 8);
	pAudio->channelsNum = header[22] | (header[23] << 8);
	pAudio->sampleRate = header[24] | (header[25] << 8) | (header[26] << 16) | (header[27] << 24);
	pAudio->bytesPerSecond = header[28] | (header[29] << 8) | (header[30] << 16) | (header[31] << 24);
	pAudio->bytesPerSample = header[32] | (header[33] << 8);
	pAudio->bitsPerSamplePerChannel = header[34] | (header[35] << 8);
	pAudio->dataSize = header[40] | (header[41] << 8) | (header[42] << 16) | (header[43] << 24);

	printf(
	    "\r\n--- WAV header ---\r\n"
	    "File size: %u\r\n"
	    "Header size left: %u\r\n"
	    "Compression (1 = no compression): %d\r\n"
	    "Channels num: %d\r\n"
	    "Sample rate: %u\r\n"
	    "Bytes per second: %u\r\n"
	    "Bytes per sample: %d\r\n"
	    "Bits per sample per channel: %d\r\n"
	    "Data size: %u\r\n"
	    "Total time: %02d:%02d\r\n"
	    "------------------\r\n",
	    pAudio->fileSize, pAudio->headerSizeLeft, pAudio->compression, pAudio->channelsNum, pAudio->sampleRate,
	    pAudio->bytesPerSecond, pAudio->bytesPerSample, pAudio->bitsPerSamplePerChannel, pAudio->dataSize,
	    pAudio->dataSize / 4 / 44100 / 60, pAudio->dataSize / 4 / 44100 % 60);

	printf("\r\n");

	/***
		if(headerSizeLeft != 16) {
			printf("Wrong `headerSizeLeft` value, 16 expected\r\n");
			f_close(&SDFile);
			return -6;
		}
		***/

	if(pAudio->compression != 1) {
		printf("Wrong `compression` value, 1 expected\r\n");
		f_close(&SDFile);
		return -7;
	}

	if(pAudio->channelsNum != 2) {
		printf("Wrong `channelsNum` value, 2 expected\r\n");
		f_close(&SDFile);
		return -8;
	}

	/***
	if((sampleRate != 44100) || (bytesPerSample != 4) || (bitsPerSamplePerChannel != 16) || (bytesPerSecond != 44100 * 2 * 2)) {
		printf("Wrong file format, 16 bit file with sample rate 44100 expected\r\n");
		f_close(&SDFile);
		return -9;
	}
	***/

	return 0;
}


